package com.wjc.httpserver;

import info.qingshui.browser.hk.setting.Setting;
import info.qingshui.browser.hk.setting.VHostInfo;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.channels.SocketChannel;
import java.util.Date;

import com.wjc.http.Dispatcher;
import com.wjc.http.HttpRequest;
import com.wjc.http.HttpRequestFactory;
import com.wjc.http.HttpResponse;
import com.wjc.http.util.PipServer;
import socks.CProxy;
import socks.SocksException;
import socks.SocksSocket;
import android.content.Context;
import android.util.Log;

/**
 * 用来维护一个client 和proxy 的连接
 * 
 * @author wjc
 * */
public class Socket5Connection {
	private  String TAG = "Socket5Connection";
	/**
	 * 客户端连接
	 * */
	private Socket clientSocket;
	/**
	 * 目标主机连接
	 * */
	private Socket targetSocket;
	//private CProxy proxySet;
	private Context context;

	private static int state;// 用来结束运行
	public static final int RUN = 0x1;
	public static final int STOP = 0x2;
	public String currentHost;
	//public static PipServer pip = new PipServer();
	
	boolean ok = false;
	boolean connectedTarget = false;
	boolean connectedTargetTimeout =false;
	boolean readOk = false;
	int passTime = 0;// 传送数据次数

	long sleepTime = 0;// 开始处理前睡眠的时间，减少太多并发
	
	int count = 0 ;
	String firstLine = "";
	/**
	 * 连接超时时长
	 * */
	private static int socketOutTime = 30 * 1000;

	public void doDispose() {
//		if (this.sleepTime > 0) {
//			try {
//				Thread.sleep(this.sleepTime);
//			} catch (InterruptedException e) {
//				e.printStackTrace();
//			}
//			return false;
//		}
		
		try {
			
				count ++;
				
				clientSocket.setSoTimeout( 4000 );
				HttpRequest request = HttpRequestFactory.read(
						clientSocket.getInputStream(),
						clientSocket.getOutputStream());
				clientSocket.setSoTimeout( socketOutTime );
				if( request.isClosed() ) {
					Log.i(TAG ,  "请求关闭，次数" + count + ";" + firstLine);
					clientSocket.close();
					targetSocket.close();
					return ;
				}
				
				firstLine = request.getFirstLine();
				Log.d(TAG ,  "请求次数" + count + ";" + firstLine);
				// https
				if ("CONNECT".equals(request.getMethod())) {
					String s = request.getRequestURL();
					int index = s.indexOf(':');
					String host = s.substring(0, index);
					String p = s.substring(index + 1);
					int port = Integer.valueOf(p);
					if (port != 443) {
						Log.w(TAG, "非安全端口访问" + firstLine);
						clientSocket.close();
						return ;
					} else {
						Log.d(TAG, "正在建立连接" + firstLine);
						clientSocket.setKeepAlive(true);
						VHostInfo vHostInfo = Setting.getSetting(this.context) .getVhostsByHost( host );
						if (vHostInfo != null) {
							CProxy proxySet = vHostInfo.getSocks5Proxy();
							targetSocket = new SocksSocket(proxySet, host, port);
						} else {
							targetSocket = new Socket( host, port );
						}
						
						
						clientSocket.setKeepAlive( true);
						targetSocket.setKeepAlive(true);
						clientSocket.setSoTimeout(socketOutTime);
						targetSocket.setSoTimeout(socketOutTime);
						OutputStream out = clientSocket.getOutputStream();
						out.write("HTTP/1.1 200 Connection Established\r\n\r\n"
								.getBytes());
						out.flush();
						// targetSocket.setSoTimeout(socketOutTime);
						Log.d(TAG, "加入隧道" + firstLine);
						//pip.addSocket(clientSocket, clientSocket);
						ok = true;
						
						try {
							passData( clientSocket, targetSocket);
						} catch (Exception e) {
							Log.w(TAG, "加入隧道出错:" + count + ";" + firstLine,e);
						}
						clientSocket.close();
						targetSocket.close();
						Log.d(TAG, "加入隧道完成:" + firstLine);
						return ;
					}
					
				} else if(  "GET".equals(request.getMethod()) ) {
					Log.d(TAG ,
							"连接到" + request.getRemoteHost() + ":"
									+ request.getRemotePort());// +request.toString());
					
					if (targetSocket == null) {
						VHostInfo vHostInfo = Setting.getSetting(this.context) .getVhostsByHost( request.getRemoteHost() );
						if (vHostInfo != null) {
							CProxy proxySet = vHostInfo.getSocks5Proxy();
							targetSocket = new SocksSocket(proxySet, request.getRemoteHost(), request.getRemotePort());
						} else {
							targetSocket = new Socket( request.getRemoteHost(), request.getRemotePort() );
						}
						this.currentHost = request.getRemoteHost();
					} else {
						// host 不同时切换连接
						//断开连接
//						if (!currentHost.equals(request.getRemoteHost())) {
//							Log.d(TAG, "close conn:currentHost=" + currentHost + ";request.getRemoteHost()" + request.getRemoteHost());
//							targetSocket.getOutputStream().write("Connection: Closed\r\n\r\n"
//									.getBytes());
//							targetSocket.close();
//							return true;
//						}
						
						if (!currentHost.equals(request.getRemoteHost())) {
							targetSocket.close();
							VHostInfo vHostInfo = Setting.getSetting(this.context) .getVhostsByHost( request.getRemoteHost() );
							if (vHostInfo != null) {
								CProxy proxySet = vHostInfo.getSocks5Proxy();
								targetSocket = new SocksSocket(proxySet, request.getRemoteHost(), request.getRemotePort());
							} else {
								targetSocket = new Socket( request.getRemoteHost(), request.getRemotePort() );
							}
							this.currentHost = request.getRemoteHost();
						}
						
					}
					
					clientSocket.setSoTimeout(socketOutTime);
					targetSocket.setSoTimeout(socketOutTime);
					clientSocket.setKeepAlive(true);
					targetSocket.setKeepAlive(true);
					Dispatcher.dispatch(request, targetSocket);
					this.doDispose();
					// se.addSocket(clientSocket,
					// targetSocket,request.getRemoteHost());

				} else {
					ok = true;
					
				}
			clientSocket.close();
			targetSocket.close();
		} catch (Throwable e) {
			if (clientSocket != null)
				try {
					OutputStream out = clientSocket.getOutputStream();
					//setErrorInfo(out, e);
					clientSocket.close();
				} catch (IOException e1) {
				}
			if (targetSocket != null)
				try {
					targetSocket.close();
				} catch (IOException e1) {
				}

			Log.w(TAG, "连接出错 :" + count + ";"  + firstLine,e );
			return ;

		} finally {
			
			state = STOP;
		}
		return ;
	}

	/**
	 * 客户端连接传入后，将分析
	 * 
	 * @param client
	 *            客户端 连接
	 * 
	 * @throws IOException
	 * */
	public Socket5Connection(Context context,Socket client,  long sleepTime) throws IOException {
		this.currentHost = null;
		this.targetSocket = null;
		this.sleepTime = sleepTime;
		
		this.context = context;
		this.clientSocket = client;
		
		TAG = TAG + System.currentTimeMillis();
		state = RUN;
		//doDispose();

	}

	public int getState() {
		return state;
	}

	public static synchronized void setState(int state) {
		Socket5Connection.state = state;
	}
	
	private void passData(final Socket inputSocket, final Socket outputSocket
			)  {

		final Thread thread1 = new Thread() {
			public void run() {
				try {
					byte[] byteArray1;
					int byteArray1Length;

					byteArray1 = new byte[5120];
					byteArray1Length = 0;

					while ((byteArray1Length = inputSocket.getInputStream()
							.read(byteArray1)) != -1) {
						readOk = true;

						connectedTarget = true;
						outputSocket.getOutputStream().write(byteArray1, 0,
								byteArray1Length);
						outputSocket.getOutputStream().flush();

						Log.d(TAG, "thread1 read ok:  passTime" + passTime);
					}
					Log.d(TAG, "thread1 read ok:  passTime" + passTime + ";"
							+ "");
				} catch (Exception e) {
					connectedTargetTimeout = true;
					Log.w(TAG,
							"thread1: passTime" + passTime + ";" + "", e);
				}
			}
		};

		thread1.start();

		final Thread thread2 = new Thread() {
			public void run() {
				try {
					byte[] byteArray1;
					int byteArray1Length;

					byteArray1 = new byte[5120];
					byteArray1Length = 0;

					while (!connectedTarget && !connectedTargetTimeout) {
						Thread.sleep(100);
					}
					if (connectedTarget) {
						while ((byteArray1Length = outputSocket.getInputStream()
								.read(byteArray1)) != -1) {
							if (readOk) {
								readOk = false;
								passTime++;
							}
							inputSocket.getOutputStream().write(byteArray1, 0,
									byteArray1Length);
							inputSocket.getOutputStream().flush();
							Log.d(TAG, "thread2 write ...:  passTime"
									+ passTime
									);
						}
						Log.d(TAG, "thread2 write ok, passTime" + passTime
								+ ";" + "");

					}

					if (inputSocket.isConnected()) {
						inputSocket.shutdownInput();
						inputSocket.shutdownOutput();
					}

					if (outputSocket.isConnected()) {
						outputSocket.shutdownInput();
						outputSocket.shutdownOutput();
					}
					
				} catch (Exception e) {
					Log.w(TAG,
							"thread2: passTime=" + passTime, e);
				}
			}
		};

		thread2.start();

		try {
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	private void setErrorInfo(OutputStream out, Exception e) {
		StringBuffer response = new StringBuffer();
		StringBuffer errorpage = new StringBuffer();
		errorpage.append("<html><head><title>出錯</title></head><body>");
		errorpage.append("<h1 align=\"center\">智能代理出錯</h1>");
		errorpage
				.append("<h2 align=\"center\">請確認網絡是可用的，如果長期不可用，請更新本軟件至最新版本</h1>");
		errorpage.append("</body></html");
		response.append("HTTP/1.1 200 OK\r\n");
		response.append("Content-Type: text/html;charset=utf-8\r\n");
		byte info[] = errorpage.toString().getBytes();
		response.append("Content-Length: " + info.length + "\r\n");
		response.append("Connection: Close\r\n\r\n");
		try {
			out.write(response.toString().getBytes());
			Log.d(TAG, "发送错误信息" + response + errorpage);
			out.write(info);
			out.flush();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

	}
}
